// PlayerCppAI.h

#pragma once

using namespace System;
using namespace System::Drawing;

namespace PlayerCppAI {

	public ref class MyPlayerBrain : public RoboRallyAPI::IPlayer
	{
	public:
		// Default constructor.
		MyPlayerBrain() {
			// Seed random number generator with current time.
			srand((unsigned)time(NULL));
		}

		// IPlayer interface implementation.

		// A name of the player.
		virtual property String^ Name {
			String^ get() {
				return "Bjarne Stroustrup"; // Simply returns hard-coded value.
			}
		}

		// An avatar of the player. Must be 32 x 32.
		virtual property Image^ Avatar {
			Image^ get() {
				return nullptr; // Use a default avatar provided by the system.
			}
		}

		// Called when your robot must be placed on the board.
		// This is called at the start of the game and each time your robot dies.
		// @param map The game map. There will be no units on this map.
		// @param you Your player object.
		// @param robotStart The position(s) on the map where you can place your robot.
		//		This will be a single point unless another robot is on your archive point.
		// @return Where to place your unit (location and direction).
		virtual RoboRallyAPI::PlayerSetup^ Setup(RoboRallyAPI::GameMap^ map, RoboRallyAPI::Player^ you, cli::array<Point>^ robotStart) {
			// A simple setup in the first available position.
			RoboRallyAPI::PlayerSetup^ setup = gcnew RoboRallyAPI::PlayerSetup(robotStart[0], RoboRallyAPI::MapSquare::DIRECTION::NORTH);
			return setup;
		}

		// Called each time the system needs another turn.
		// If you do not return a valid turn, the system will randomly move one of
		// your units.
		// This call must return in under 1 second. If it has not returnd in 1 second
		// the call will be aborted and a random move will be assigned.
		// @param map The game map with all units on it.
		// @param you Your player object. This is created for each call.
		// @param allPlayers All players including you. This is created for each call.
		// @param priorityNumbers The priority numbers that will be assigned to the cards you return. This order is fixed.
		// @return Your requested turn.
		virtual RoboRallyAPI::PlayerTurn^ Turn(RoboRallyAPI::GameMap^ map, RoboRallyAPI::Player^ you, cli::array<RoboRallyAPI::Player^>^ allPlayers, cli::array<RoboRallyAPI::Card>^ cards) {

			// If hurt bad, consider power down.
			bool powerDown = false;
			if ((you->Damage > 5) && ((rand() % 3) == 0))
				powerDown = true;

			// Get 40 sets, pick the one that's closest to the flag.
			cli::array<RoboRallyAPI::Card>^ best = nullptr;
			int bestDiff = std::numeric_limits<int>::max();
			int okDiff = rand() % 3;

			// Find the first untouched element.
			RoboRallyAPI::Player::FlagState^ fs = nullptr;
			for (int i = 0; i < you->FlagStates->Length; ++i)
				if (!you->FlagStates[i]->Touched) {
					fs = you->FlagStates[i];
					break;
				}

			Point ptFlag = fs == nullptr ? Point(5, 6) : fs->Position;
			for (int turnOn = 0; turnOn < 40; ++turnOn) {
				cli::array<RoboRallyAPI::Card>^ moveCards = gcnew cli::array<RoboRallyAPI::Card>(5);
				array<bool> ^cardUsed = gcnew array<bool>(cards->Length);
				for (int ind = 0; ind < 5 - you->NumLockedCards; ind++)
					while (true)
					{
						int index = rand() % cards->Length;
						if (cardUsed[index])
							continue;
						moveCards[ind] = cards[index];
						cardUsed[index] = true;
						break;
					}

				// add in the locked cards
				for (int ind = 5 - you->NumLockedCards; ind < 5; ind++)
					moveCards[ind] = you->Cards[ind];

				RoboRallyAPI::Utilities::MovePoint^ mp = RoboRallyAPI::Utilities::CardDestination(map, you->Robot->Location, moveCards);
				if (!mp->Dead) {
					int diff = Math::Abs(ptFlag.X - mp->Location.MapPosition.X) + Math::Abs(ptFlag.Y - mp->Location.MapPosition.Y);
					if (diff <= okDiff)
						return gcnew RoboRallyAPI::PlayerTurn(moveCards, powerDown);
					if (diff < bestDiff) {
						bestDiff = diff;
						best = moveCards;
					}
				}
			}
			return gcnew RoboRallyAPI::PlayerTurn(best, powerDown);
		}
	};
}
